﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DungeonDelver.Content;
using DungeonDelver.Engine;
using PlayDeezGames.Common;
using System.Xml.Linq;
using System.IO;

namespace DungeonDelver.MapEditor
{
    public partial class MainPage : UserControl
    {
        private IdentifiedDescriptor imageList = null;
        private ImageBrushes imageBrushes = null;
        private Map map = null;
        private ConfigurationTable terrainTable = null;
        private int selectedTileRow = 0;
        private int selectedTileColumn = 0;
        private int? hoverTileRow = null;
        private int? hoverTileColumn = null;
        private Dictionary<object, int> paletteColumnLookUp = new Dictionary<object, int>();
        private Dictionary<object, int> paletteRowLookUp = new Dictionary<object, int>();
        private Dictionary<int, Dictionary<int, string>> palette = new Dictionary<int, Dictionary<int, string>>();

        private Dictionary<object, int> mapColumnLookUp = new Dictionary<object, int>();
        private Dictionary<object, int> mapRowLookUp = new Dictionary<object, int>();
        private int? hoverMapColumn = null;
        private int? hoverMapRow = null;

        private void MapCell_MouseEnter(object sender, MouseEventArgs e)
        {
            hoverMapColumn = mapColumnLookUp[sender];
            hoverMapRow = mapRowLookUp[sender];
            ShowMap();
        }
        private void MapCell_MouseLeave(object sender, MouseEventArgs e)
        {
            hoverMapColumn = null;
            hoverMapRow = null;
            ShowMap();
        }
        private void MapCell_MouseMove(object sender, MouseEventArgs e)
        {
            if (mouseLeftDown)
            {
                int column = mapColumnLookUp[sender];
                int row = mapRowLookUp[sender];
                PlaceTerrain(column, row);
                ShowMap();
            }
        }
        private void RemoveTerrain(int column, int row)
        {
            map[column][row].Terrain = null;
        }
        private void PlaceTerrain(int column, int row)
        {
            if (map[column][row].Terrain == null)
            {
                map[column][row].Terrain = EntityFactories.Create(map[column][row], Engine.Names.EngineFactories.TerrainFactory) as Terrain;
                map[column][row].Terrain.Identifier = palette[selectedTileColumn][selectedTileRow];
            }
            else
            {
                map[column][row].Terrain.Identifier = palette[selectedTileColumn][selectedTileRow];
            }
        }
        private void MapCell_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            mouseLeftDown = false;
            int column = mapColumnLookUp[sender];
            int row = mapRowLookUp[sender];
            PlaceTerrain(column, row);
            ShowMap();
        }
        private bool mouseLeftDown = false;
        private void MapCell_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            mouseLeftDown = true;
            int column = mapColumnLookUp[sender];
            int row = mapRowLookUp[sender];
            PlaceTerrain(column, row);
            ShowMap();
        }
        private void InitializeMapControl()
        {
            for (int column = 0; column < Map.Columns; ++column)
            {
                for (int row = 0; row < Map.Rows; ++row)
                {
                    mapColumnLookUp[Map[column][row]] = column;
                    mapRowLookUp[Map[column][row]] = row;
                    Map[column][row].MouseEnter += MapCell_MouseEnter;
                    Map[column][row].MouseLeave += MapCell_MouseLeave;
                    Map[column][row].MouseLeftButtonDown += MapCell_MouseLeftButtonDown;
                    Map[column][row].MouseLeftButtonUp += MapCell_MouseLeftButtonUp;
                    Map[column][row].MouseMove += MapCell_MouseMove;
                }
            }
        }

        private void PaletteCell_MouseEnter(object sender, MouseEventArgs e)
        {
            hoverTileRow = paletteRowLookUp[sender];
            hoverTileColumn = paletteColumnLookUp[sender];
            ShowPalette();
        }

        private void PaletteCell_MouseLeave(object sender, MouseEventArgs e)
        {
            hoverTileRow = null;
            hoverTileColumn = null;
            ShowPalette();
        }

        private void PaletteCell_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            selectedTileRow = paletteRowLookUp[sender];
            selectedTileColumn = paletteColumnLookUp[sender];
            ShowPalette();
        }

        private void InitializePaletteControl()
        {

            for (int column = 0; column < Palette.Columns; ++column)
            {
                palette[column] = new Dictionary<int, string>();
                for (int row = 0; row < Palette.Rows; ++row)
                {
                    palette[column][row] = string.Empty;
                    paletteColumnLookUp[Palette[column][row]] = column;
                    paletteRowLookUp[Palette[column][row]] = row;
                    Palette[column][row].MouseEnter += new MouseEventHandler(PaletteCell_MouseEnter);
                    Palette[column][row].MouseLeave += new MouseEventHandler(PaletteCell_MouseLeave);
                    Palette[column][row].MouseLeftButtonDown += new MouseButtonEventHandler(PaletteCell_MouseLeftButtonDown);
                }
            }
        }

        private void LoadTerrainTable()
        {
            XDocument doc = XDocument.Load("/DungeonDelver.Content;component/configuration/tables/terrains.xml");
            terrainTable = EntityFactories.Load(null, doc.Root) as ConfigurationTable;
        }

        private void LoadImageList()
        {
            XDocument doc = XDocument.Load("/DungeonDelver.Content;component/configuration/tables/property-groups/images-editor.xml");
            imageList = EntityFactories.Load(null, doc.Root) as IdentifiedDescriptor;
        }

        private void CreateImageBrushes()
        {
            imageBrushes = new ImageBrushes();
            foreach (var property in imageList.Properties)
            {
                imageBrushes.LookUpTable[property] = (imageList[property] as StringProperty).Value;
            }
            imageBrushes.LookUpTable["ddme-blank"]="/DungeonDelver.MapEditor;component/images/blank.png";
            imageBrushes.LookUpTable["ddme-empty"] = "/DungeonDelver.MapEditor;component/images/empty.png";
            imageBrushes.LookUpTable["ddme-hilite"] = "/DungeonDelver.MapEditor;component/images/hilite.png";
            imageBrushes.LookUpTable["ddme-hiliteselected"] = "/DungeonDelver.MapEditor;component/images/hiliteselected.png";
            imageBrushes.LookUpTable["ddme-selected"] = "/DungeonDelver.MapEditor;component/images/selected.png";
        }

        private void ShowPalette()
        {
            int row = 0;
            int column = 0;
            foreach (var terrain in terrainTable.Identifiers)
            {
                palette[column][row] = terrain;
                IdentifiedDescriptor descriptor = terrainTable[terrain];
                string imageUri = (descriptor[DungeonDelver.Engine.Names.EngineProperties.ImageUri] as StringProperty).Value;
                Palette[column][row][0].Fill = imageBrushes[imageUri];
                if (column == selectedTileColumn && row == selectedTileRow)
                {
                    if (hoverTileColumn != null && column == (int)hoverTileColumn && hoverTileRow != null && row == (int)hoverTileRow)
                    {
                        Palette[column][row][1].Fill = imageBrushes["ddme-hiliteselected"];
                    }
                    else
                    {
                        Palette[column][row][1].Fill = imageBrushes["ddme-selected"];
                    }
                }
                else
                {
                    if (hoverTileColumn != null && column == (int)hoverTileColumn && hoverTileRow != null && row == (int)hoverTileRow)
                    {
                        Palette[column][row][1].Fill = imageBrushes["ddme-hilite"];
                    }
                    else
                    {
                        Palette[column][row][1].Fill = imageBrushes["ddme-blank"];
                    }
                }
                column++;
                if (column == Palette.Columns)
                {
                    column = 0;
                    row++;
                }

            }
            while (row < Palette.Rows)
            {
                while (column < Palette.Columns)
                {
                    Palette[column][row][0].Fill = imageBrushes["ddme-empty"];
                    Palette[column][row][1].Fill = imageBrushes["ddme-blank"];
                    column++;
                }
                column = 0;
                row++;
            }
        }

        private void NewMap()
        {
            map = EntityFactories.Create(null, Engine.Names.EngineFactories.MapFactory) as Map;
            for (int column = 0; column < Map.Columns; ++column)
            {
                map[column] = EntityFactories.Create(map, Engine.Names.EngineFactories.MapColumnFactory) as MapColumn;
                for (int row = 0; row < Map.Rows; ++row)
                {
                    map[column][row] = EntityFactories.Create(map[column], Engine.Names.EngineFactories.MapCellFactory) as MapCell;
                }
            }
        }

        private void ShowMap()
        {
            for (int column = 0; column < Map.Columns; ++column)
            {
                for (int row = 0; row < Map.Rows; ++row)
                {
                    Map[column][row][0].Fill = imageBrushes["ddme-empty"];
                    if (map[column][row].Terrain != null)
                    {
                        string terrainIdentifier = map[column][row].Terrain.Identifier;
                        IdentifiedDescriptor descriptor = terrainTable[terrainIdentifier];
                        string imageUri = (descriptor[DungeonDelver.Engine.Names.EngineProperties.ImageUri] as StringProperty).Value;
                        Map[column][row][1].Fill = imageBrushes[imageUri];
                    }
                    else
                    {
                        Map[column][row][1].Fill = imageBrushes["ddme-blank"];
                    }
                    if (hoverMapColumn != null && hoverMapRow != null && column == (int)hoverMapColumn && row == (int)hoverMapRow)
                    {
                        Map[column][row][2].Fill = imageBrushes["ddme-hilite"];
                    }
                    else
                    {
                        Map[column][row][2].Fill = imageBrushes["ddme-blank"];
                    }
                }
            }
        }

        public MainPage()
        {
            InitializeComponent();
            InitializeMapControl();
            InitializePaletteControl();

            DungeonDelver.Content.Factories.Register();
            LoadTerrainTable();
            LoadImageList();
            CreateImageBrushes();
            ShowPalette();
            NewMap();
            ShowMap();


        }

        private void NewButton_Click(object sender, RoutedEventArgs e)
        {
            for (int column = 0; column < Map.Columns; ++column)
            {
                for (int row = 0; row < Map.Rows; ++row)
                {
                    map[column][row].Terrain = null;
                }
            }
            ShowMap();
        }

        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "Xml Files|*.xml";
            bool? result = dialog.ShowDialog();
            if (result!=null && (bool)result)
            {
                XDocument doc = new XDocument(map.ToXElement());
                Stream stream = dialog.OpenFile();
                doc.Save(stream);
                stream.Close();
            }
        }

        private void LoadButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Xml Files|*.xml";
            bool? result = dialog.ShowDialog();
            if (result != null && (bool)result)
            {
                XDocument doc = XDocument.Load(dialog.File.OpenRead());
                map = EntityFactories.Load(null, doc.Root) as Map;
                ShowMap();
            }
        }

        private void OverlayButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Xml Files|*.xml";
            bool? result = dialog.ShowDialog();
            if (result != null && (bool)result)
            {
                XDocument doc = XDocument.Load(dialog.File.OpenRead());
                Map overlay = EntityFactories.Load(null, doc.Root) as Map;
                foreach(var column in overlay.Columns)
                {
                    foreach (var row in overlay[column].Rows)
                    {
                        if (overlay[column][row].Terrain != null)
                        {
                            map[column][row].Terrain.Identifier = overlay[column][row].Terrain.Identifier;
                        }
                    }
                }
                ShowMap();
            }
        }
    }
}
